<style scoped>
.suggestion-list{width: 100%;max-height: 300px;overflow: hidden auto;padding: 5px;border-radius: 8px;}
.suggestion-list .suggestion-row{width: 100%;padding: 2px 6px;border-bottom: 10x solid var(--color-bg-re-r);}
.suggestion-list .suggestion-row.on{background: var(--color-primary);color: var(--color-primary-re);}
.suggestion-list .suggestion-row .content{padding-left: 10px;opacity: .7;}
</style>
<template>
  <div class="text_one_code">
    <p v-if="is_info" class="text-ellipsis" style="display: block" :title="modelValue">{{ modelValue }}</p>
    <template v-else>
      <el-input ref="input" :name="name" v-model="this_value" @change="update_value" style="width: 100%;"
                @input="handleInput" @click="handleInput" @keydown="handleKeyDown" @keyup="handleKeyUp" @blur="focus=false" @focus="focus=true">
      </el-input>
      <div ref="suggestionListDiv" class="suggestion-list" v-show="focus && matches.length">
        <div class="suggestion-row" :class="{on:i===indexOn}" v-for="(row,i) in matches" @click="">
          <span class="value">{{row.value}}</span>
          <span class="content">{{row.content}}</span>
        </div>
      </div>
    </template>
  </div>
</template>

<script>

const codeList = [
  {value:"$info", content:'当前数据详情'},
  {value:"$input", content:'URL的GET参数'},
  {value:"get($info,'key')", content:'获取数据 get($data, $key, $default=null)'},
  {value:"get_true($info,'key','key2')", content:'获取不为空(0、空字符、空数组等)的数据 get_true($data, ...$keys)'},
  {value:"list_get(array,'key')", content:'获取数组的某一列 list_get(array $list, $key, $index_key="")'},
  {value:"list_get_true(array,'key','key2')", content:'获取数组的某一列不为空的数据 list_get_true(array $list, ...$keys)'},
  {value:"join(array)", content:'数组转字符串 join(array $list, $separator=",")'},
  {value:"list_sort(array,'key')", content:'数组排序 list_sort(array $list, $key="", $desc=false)'},
  {value:"list_gte(array,'key','value')", content:'返回数组中指定值大于或等于的项目，按与$value的差价排序 list_gte($list, $key, $value)'},
  {value:"list_lte(array,'key','value')", content:'返回数组中指定值小于或等于的项目，按与$value的差价排序 list_lte($list, $key, $value)'},
  {value:"concat(变量1,变量2)", content:'拼接参数(数字、字符串、数组) concat(...$args)'},
  {value:"ratio(value, 比例)", content:'对数字或者字符串进行比例操作 ratio($value, $ratio)'},
  {value:"list_ratio(array, 比例)", content:'对数组的每个指进行比例操作 list_ratio($list, $ratio)'},
  {value:"round()", content:'对数字进行四舍五入 round($num, $precision=0)'},
  {value:"json_encode(value)", content:'json编码 json_encode($value)'},
  {value:"json_decode(json)", content:'json解码 json_decode($json)'},
  {value:"json_decode_object(json)", content:'json解码成数组，如果不是数组返回空数组 json_decode_object($json)'},
  {value:"length(变量)", content:'变量(数组，字符串)长度 length($data)'},
  {value:"db_find('table', [])", content:'获取指定项目对象 db_find($table, array $where=[])'},
  {value:"db_list('table', [])", content:'获取指定项目对象列表 db_list($table, array $where=[])'},
  {value:"db_count('table', [])", content:'获取数据数量 db_count($table, array $where, $no_base_where=false)'},
  {value:"db_sum('table', [], $field)", content:'对数据求和 db_sum($table, array $where, $field, $no_base_where=false)'},
  {value:"unique(array)", content:'数组去重 unique(array $list)'},
  {value:"unique_eq(array)", content:'数组每一项是否都相等，返回子项否者返回null unique_eq(array $list)'},
  {value:"_if(条件, 为假返回)", content:'条件判断 _if($ex, $fail, $ok=false)'},
  {value:"indexof(数组或字符串, 'need')", content:'返回首次出现的位置或者null indexof($map, $need)'},
  {value:"config('key')", content:'获取配置项 config($name, $default=null)'},
  {value:"date()", content:'格式化日期 date($fmt="Y-m-d H:i:s", $time=null)'},
  {value:"this_user('id')", content:'当前用户(或者空User 对象) this_user($key="id")'},
  {value:"this_admin('id')", content:'当前管理员(或者空Admin 对象) this_admin($key="id")'},
  {value:"this_tenant('id')", content:'当前租户数据 this_tenant($key="id")'},
  {value:"model_map('switch_price&switch_price_sku')", content:'模型枚举 model_map($switch=null)'},
  {value:"pay_type_map(true)", content:'支付方式枚举 pay_type_map($is_all=false)'},
  {value:"status_map('table')", content:'模型的状态枚举 status_map($table="")'},
  {value:"pay_status_map('table')", content:'模型的支付状态枚举 pay_status_map($table="")'},
  {value:"time_range_map([$time_list], 1800)", content:'时间区间选项的配置，用于二级联动选项 time_range_map($time_list, $range, $start=0, $day_num=5)'},
  {value:"option_str([], 'title', 'id')", content:'选项字符，格式：值|键,... option_str($map, $content_key="content", $value_key="value", $children_key="children")'},
  {value:"user_money(用户ID)", content:'指定用户余额 user_money($user_id=0)'},
  {value:"compute_price('model_name')", content:'计算价格，适用于商品订单计算支付金额 compute_price(string $model_name, $id=0, $num=0, $sku_id=0, $promotion_id=0, $additional_select=null)'},
  {value:"pay_money('model_name')", content:'计算价格，只返回pay_money参数的版本 pay_money(string $model_name, $id=0, $num=1, $sku_id=0, $promotion_id=0, $additional_select=null)'},
  {value:"batch_action('model_name', 'info', ID集)", content:'批量info操作 batch_action($model_name, $action, $ids, $is_init=false)'},
  {value:"owned_time('model_name', ID)", content:'判断是否拥有指定项目 owned($link_table, $link_id)'},
  {value:"owned_surplus('model_name', ID)", content:'拥有项目的截至时间 owned_time($link_table, $link_id)'},
  {value:"owned('model_name', ID)", content:'拥有项目的剩余时长 owned_surplus($link_table, $link_id)'},
  {value:"replace('/pattern/', 'replace', 数据)", content:'正则替换 replace($pattern, $replace, $subject)'},
];



export default {
  _title_: '计算代码',
  props: {
    name: [String, Number],
    modelValue: [String, Number, Array],
    is_info: Boolean,

    split: [String, RegExp],
    suggestionHandle: Function, // 返回{value:匹配文本，content:文本说明}[]
  },
  emits: ['update:modelValue', 'change'],
  data(){
    return {
      need_display: true,
      this_value: this.modelValue,

      focus: false,
      matches: [],
      indexOn: 0,

      suggestionList: codeList,
    }
  },
  methods: {
    splitString(str){
      let split = this.split || /[^\w\$]/;
      return str.split(split);
    },
    suggestion(currentWord){
      if (typeof this.suggestionHandle === 'function'){
        return this.suggestionHandle(currentWord);
      }else {
        let res = [];
        Object.values(this.suggestionList).forEach((item)=>{
          let val = typeof item === 'string' ? item : item.value;
          if (~val.toLowerCase().indexOf(currentWord.toLowerCase())){
            res.push({
              value: val,
              content: item.content || '',
            })
          }
        })
        return res;
      }
    },
    handleInput(){
      let input = this.$refs.input.input;

      const cursorPosition = input.selectionStart;
      const textBeforeCursor = input.value.substring(0, cursorPosition);

      // 获取最后一个单词
      const words = this.splitString(textBeforeCursor);
      const currentWord = words[words.length - 1];


      this.matches = [];
      this.indexOn = 0;
      if (currentWord.length > 0) {
        // 从列表中查找匹配项
        Promise.resolve(this.suggestion(currentWord)).then(matches=>{
          this.matches = matches;
        })
      }

    },
    handleKeyUp(e){
      if (!this.focus) return ;
      if (e.key === 'ArrowLeft' || e.key === 'ArrowRight'){
        this.handleInput();
      }
    },
    handleKeyDown(e) {
      if (!this.focus) return ;
      if (!this.matches.length) return ;
      if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
        e.preventDefault();
        let index = this.indexOn + (e.key === 'ArrowDown' ? 1 : -1) + this.matches.length;
        this.indexOn = index % this.matches.length;

        let list = this.$refs.suggestionListDiv.querySelectorAll('.suggestion-row');
        let onY = list[this.indexOn].offsetTop;
        this.$refs.suggestionListDiv.scrollTop = onY - 150;
      }
      if (e.key === 'Tab' || e.key === 'Enter') {
        e.preventDefault();
        let input = this.$refs.input.input;
        let row = this.matches[this.indexOn];
        const cursorPosition = input.selectionStart;
        let textBeforeCursor = input.value.substring(0, cursorPosition);
        const textAfterCursor = input.value.substring(cursorPosition);

        // 获取最后一个单词
        const words = this.splitString(textBeforeCursor);
        const currentWord = words[words.length - 1];

        textBeforeCursor = textBeforeCursor.substring(0, cursorPosition-currentWord.length) + row.value;

        let val = textBeforeCursor + textAfterCursor;

        this.this_value = val;
        this.update_value(this.this_value);

        // 移动光标到补全内容之后
        const newCursorPosition = textBeforeCursor.length;
        setTimeout(()=>{
          input.setSelectionRange(newCursorPosition, newCursorPosition);
        },20)

        this.matches = [];
      }
    },
    handleBlur(){
      setTimeout(()=>{
        this.focus = false;
      },200)
    },
    update_value(v){
      this.need_display = false;
      setTimeout(()=>{this.need_display = true;},5);
      this.$emit('update:modelValue', v);
      this.$emit('change', v);
    },
  },
  watch: {
    modelValue(){
      if (!this.need_display) return;
      this.this_value = this.modelValue;
    }
  },
  computed: {
  },
  mounted() {

  }
}
</script>
